import 'dart:developer';

import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter/scheduler.dart';

/*
 * 1. flutter analyze
 * 在运行应用程序前，请运行flutter analyze测试你的代码。这个工具是一个静态代码检查工具，
 * 它是dartanalyzer工具的一个包装，主要用于分析代码并帮助开发者发现可能的错误，比如，
 * Dart分析器大量使用了代码中的类型注释来帮助追踪问题，避免var、无类型的参数、无类型的列表文字等。
 * 如果你使用IntelliJ的Flutter插件，那么分析器在打开IDE时就已经自动启用了，
 * 如果读者使用的是其它IDE，强烈建议读者启用Dart 分析器，因为在大多数时候，Dart 分析器可以在代码运行前发现大多数问题。
 *
 * 2.Flutter有三种构建模式，适用于不同的场景，想要对性能监控，都跑在Profile模式下:
 * - Debug(flutter run):
 * 就是调试模式，在调试模式下：
a.Flutter的断言（Assertions）功能是开的
b.Flutter的Observatory是开的，Observatory是用于分析和调试Dart代码的工具，用于Dart的debugger
c.扩展的服务功能（Service extensions）是开启的，如第二点的Observatory的服务还有性能的服务等。
d.JIT编译模式，可以使用Hot Reload，为了快速开发
* - Release(flutter run --release):
* 就是要发布了，在Release模式下，要追求最高的性能和最小的安装包,所以会：
a.断言（Assertions）功能关闭
b.没有Debugging的信息
c.Debugger的功能关闭
d.AOT编译，为了快速启动，快速执行和更小的包装包大小。
e.扩展的服务功能（Service extensions）关闭
*- Profile(flutter run --profile)是专门监控性能的模式，在Debug模式下，不能实际反应应用的性能，而在Release模式下，
* 却没有监控的功能，所以就诞生了Profile模式，Profile模式和Release模式更接近，Profile和Release
* 都采用的AOT编译，所以都不能用Hot Reload，但是Profile相对于Release，多了如下的功能：
a. 一些扩展的服务功能（Service extensions）是打开的，例如监控性能的浮层等。
b. Tracing是打开的，Observatory也可以连接到进程
Profile模式只能跑在真机上。
*
* 3. Dart print()功能将输出到系统控制台，您可以使用flutter logs来查看它（基本上是一个包装adb logcat）。
*如果你一次输出太多，那么Android有时会丢弃一些日志行。为了避免这种情况，您可以使用Flutter的
* foundation库中的debugPrint()。 这是一个封装print，它将输出限制在一个级别，避免被Android内核丢弃。
*
* 4. 统计应用启动时间
* flutter run --trace-startup --profile
* 要收集有关Flutter应用程序启动所需时间的详细信息，可以在运行flutter run时使用trace-startup和profile选项。
* 跟踪输出保存为start_up_info.json，在Flutter工程目录在build目录下。输出列出了从应用程序启动到这些跟踪事件（以微秒捕获）所用的时间：

进入Flutter引擎时.
展示应用第一帧时.
初始化Flutter框架时.
完成Flutter框架初始化时.
如 :

{
  "engineEnterTimestampMicros": 96025565262,
  "timeToFirstFrameMicros": 2171978,
  "timeToFrameworkInitMicros": 514585,
  "timeAfterFrameworkInitMicros": 1657393
}
*
* 5. 跟踪Dart代码性能
* 要执行自定义性能跟踪和测量Dart任意代码段的wall/CPU时间（类似于在Android上使用systrace）。
*  使用dart:developer的Timeline工具来包含你想测试的代码块，例如：
Timeline.startSync('interesting function');
// iWonderHowLongThisTakes();
Timeline.finishSync();
然后打开你应用程序的Observatory timeline页面，在“Recorded Streams”中选择‘Dart’复选框，并执行你想测量的功能。
刷新页面将在Chrome的跟踪工具中显示应用按时间顺序排列的timeline记录。
请确保运行flutter run时带有--profile标志，以确保运行时性能特征与您的最终产品差异最小。
 */

class DemoDebug extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    //当使用Dart Observatory（或另一个Dart调试器，例如IntelliJ IDE中的调试器）时，可以使用该debugger()语句插入编程式断点。要使用这个，你必须添加import 'dart:developer';到相关文件顶部。
//    debugger();

    // 显示布局边界,以可视方式调试布局问题
     debugPaintSizeEnabled = true;

    //调试动画最简单的方法是减慢它们的速度。为此，请将timeDilation变量（在scheduler库中）
    // 设置为大于1.0的数字，例如50.0。 最好在应用程序启动时只设置一次。如果您在运行中更改它，
    // 尤其是在动画运行时将其值改小，则在观察时可能会出现倒退，这可能会导致断言命中，
    // 并且这通常会干扰我们的开发工作。
    timeDilation = 20;

    debugPrintStack();
    return MaterialApp(
        title: 'flutter dmeo',
        theme: ThemeData(primarySwatch: Colors.yellow),
        home: Scaffold(
          appBar: AppBar(
            title: Text("DemoDebug"),
          ),
          body: Center(
            child: new Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
              new FlatButton(
                onPressed: () {
                  //要转储Widgets树的状态，请调用debugDumpApp()。 只要应用程序已经构建了至少一次（即在调用build()之后的任何时间），
                  // 您可以在应用程序未处于构建阶段（即，不在build()方法内调用 ）的任何时间调用此方法（在调用runApp()之后）。
                  debugDumpApp();
                },
                child: new Text('Widget 树'),
              ),
              new FlatButton(
                onPressed: () {
                  //如果您尝试调试布局问题，那么Widget树可能不够详细。在这种情况下，
                  // 您可以通过调用debugDumpRenderTree()转储渲染树。 正如debugDumpApp()，
                  // 除布局或绘制阶段外，您可以随时调用此函数。作为一般规则，从frame 回调 或事件处理器中调用它是最佳解决方案。
                  debugDumpRenderTree();
                },
                child: new Text('渲染树'),
              ),
              new FlatButton(
                onPressed: () {
                  //读者可以理解为渲染树是可以分层的，而最终绘制需要将不同的层合成起来，
                  // 而Layer则是绘制时需要合成的层，如果您尝试调试合成问题，则可以使用debugDumpLayerTree()
                  debugDumpLayerTree();
                },
                child: new Text('Layer树'),
              ),
              new FlatButton(
                onPressed: () {
                  //还可以调用debugDumpSemanticsTree()获取语义树（呈现给系统可访问性API的树）的转储。 要使用此功能，必须首先启用辅助功能，例如启用系统辅助工具或SemanticsDebugger
//                  debugDumpSemanticsTree();
                },
                child: new Text('语义树'),
              ),
            ],
          ),
          ),
        ));
  }
}
